package com.investment.advisor.service.impl;

import com.investment.advisor.dto.FundDTO;
import com.investment.advisor.dto.PortfolioDTO;
import com.investment.advisor.dto.TradeDTO;
import com.investment.advisor.entity.Fund;
import com.investment.advisor.entity.Portfolio;
import com.investment.advisor.entity.Trade;
import com.investment.advisor.repository.FundRepository;
import com.investment.advisor.repository.PortfolioRepository;
import com.investment.advisor.repository.TradeRepository;
import com.investment.advisor.service.TradeService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityNotFoundException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
public class TradeServiceImpl implements TradeService {

    private final TradeRepository tradeRepository;
    private final PortfolioRepository portfolioRepository;
    private final FundRepository fundRepository;

    @Autowired
    public TradeServiceImpl(
            TradeRepository tradeRepository,
            PortfolioRepository portfolioRepository,
            FundRepository fundRepository) {
        this.tradeRepository = tradeRepository;
        this.portfolioRepository = portfolioRepository;
        this.fundRepository = fundRepository;
    }

    @Override
    public List<TradeDTO> getAllTrades() {
        return tradeRepository.findAll().stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    @Override
    public TradeDTO getTradeById(Long id) {
        Trade trade = tradeRepository.findById(id)
                .orElseThrow(() -> new EntityNotFoundException("Trade not found with id: " + id));
        return convertToDTO(trade);
    }

    @Override
    public List<TradeDTO> getTradesByPortfolioId(Long portfolioId) {
        Portfolio portfolio = portfolioRepository.findById(portfolioId)
                .orElseThrow(() -> new EntityNotFoundException("Portfolio not found with id: " + portfolioId));
        
        return tradeRepository.findByPortfolio(portfolio).stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    @Override
    public List<TradeDTO> getTradesByFundId(Long fundId) {
        Fund fund = fundRepository.findById(fundId)
                .orElseThrow(() -> new EntityNotFoundException("Fund not found with id: " + fundId));
        
        return tradeRepository.findByFund(fund).stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    @Override
    public List<TradeDTO> getTradesByPortfolioAndFund(Long portfolioId, Long fundId) {
        Portfolio portfolio = portfolioRepository.findById(portfolioId)
                .orElseThrow(() -> new EntityNotFoundException("Portfolio not found with id: " + portfolioId));
                
        Fund fund = fundRepository.findById(fundId)
                .orElseThrow(() -> new EntityNotFoundException("Fund not found with id: " + fundId));
                
        return tradeRepository.findByPortfolioAndFund(portfolio, fund).stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    @Override
    public List<TradeDTO> getTradesByAction(String action) {
        return tradeRepository.findByAction(action).stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    @Override
    public List<TradeDTO> getTradesByStatus(String status) {
        return tradeRepository.findByStatus(status).stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    @Override
    public List<TradeDTO> getTradesByCreator(String creator) {
        return tradeRepository.findByCreator(creator).stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    @Override
    public List<TradeDTO> getTradesByDateRange(LocalDate startDate, LocalDate endDate) {
        return tradeRepository.findByTradeDateBetween(startDate, endDate).stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    @Override
    public List<TradeDTO> getTradesByPortfolioAndDateRange(Long portfolioId, LocalDate startDate, LocalDate endDate) {
        Portfolio portfolio = portfolioRepository.findById(portfolioId)
                .orElseThrow(() -> new EntityNotFoundException("Portfolio not found with id: " + portfolioId));
                
        return tradeRepository.findByPortfolioAndTradeDateBetween(portfolio, startDate, endDate).stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    @Override
    @Transactional
    public TradeDTO createTrade(TradeDTO tradeDTO) {
        Trade trade = convertToEntity(tradeDTO);
        Trade savedTrade = tradeRepository.save(trade);
        return convertToDTO(savedTrade);
    }

    @Override
    @Transactional
    public TradeDTO updateTrade(Long id, TradeDTO tradeDTO) {
        if (!tradeRepository.existsById(id)) {
            throw new EntityNotFoundException("Trade not found with id: " + id);
        }
        
        Trade trade = convertToEntity(tradeDTO);
        trade.setId(id);
        Trade updatedTrade = tradeRepository.save(trade);
        return convertToDTO(updatedTrade);
    }

    @Override
    @Transactional
    public TradeDTO updateTradeStatus(Long id, String status) {
        Trade trade = tradeRepository.findById(id)
                .orElseThrow(() -> new EntityNotFoundException("Trade not found with id: " + id));
                
        trade.setStatus(status);
        Trade updatedTrade = tradeRepository.save(trade);
        return convertToDTO(updatedTrade);
    }

    @Override
    @Transactional
    public void deleteTrade(Long id) {
        if (!tradeRepository.existsById(id)) {
            throw new EntityNotFoundException("Trade not found with id: " + id);
        }
        
        tradeRepository.deleteById(id);
    }

    private TradeDTO convertToDTO(Trade trade) {
        TradeDTO tradeDTO = new TradeDTO();
        // 手动复制基本属性，避免循环引用
        tradeDTO.setId(trade.getId());
        tradeDTO.setAction(trade.getAction());
        tradeDTO.setTradeDate(trade.getTradeDate());
        tradeDTO.setShares(trade.getShares());
        tradeDTO.setPrice(trade.getPrice());
        tradeDTO.setAmount(trade.getAmount());
        tradeDTO.setStatus(trade.getStatus());
        tradeDTO.setCreator(trade.getCreator());
        tradeDTO.setCreateTime(trade.getCreateTime());
        tradeDTO.setUpdateTime(trade.getUpdateTime());
        
        // 处理Portfolio（只复制基本属性）
        if (trade.getPortfolio() != null) {
            PortfolioDTO portfolioDTO = new PortfolioDTO();
            portfolioDTO.setId(trade.getPortfolio().getId());
            portfolioDTO.setName(trade.getPortfolio().getName());
            portfolioDTO.setDescription(trade.getPortfolio().getDescription());
            portfolioDTO.setPerformance(trade.getPortfolio().getPerformance());
            portfolioDTO.setAnnualReturn(trade.getPortfolio().getAnnualReturn());
            portfolioDTO.setMaxDrawdown(trade.getPortfolio().getMaxDrawdown());
            portfolioDTO.setVolatility(trade.getPortfolio().getVolatility());
            portfolioDTO.setSharpeRatio(trade.getPortfolio().getSharpeRatio());
            portfolioDTO.setCreator(trade.getPortfolio().getCreator());
            portfolioDTO.setCreateTime(trade.getPortfolio().getCreateTime());
            portfolioDTO.setUpdateTime(trade.getPortfolio().getUpdateTime());
            // 不设置 strategy 和 funds 字段，避免循环引用
            tradeDTO.setPortfolio(portfolioDTO);
        }
        
        // 处理Fund（只复制基本属性）
        if (trade.getFund() != null) {
            FundDTO fundDTO = new FundDTO();
            fundDTO.setId(trade.getFund().getId());
            fundDTO.setCode(trade.getFund().getCode());
            fundDTO.setName(trade.getFund().getName());
            fundDTO.setType(trade.getFund().getType());
            fundDTO.setNav(trade.getFund().getNav());
            fundDTO.setDailyReturn(trade.getFund().getDailyReturn());
            fundDTO.setWeeklyReturn(trade.getFund().getWeeklyReturn());
            fundDTO.setMonthlyReturn(trade.getFund().getMonthlyReturn());
            fundDTO.setYearlyReturn(trade.getFund().getYearlyReturn());
            fundDTO.setSize(trade.getFund().getSize());
            fundDTO.setManager(trade.getFund().getManager());
            fundDTO.setCompany(trade.getFund().getCompany());
            fundDTO.setDescription(trade.getFund().getDescription());
            fundDTO.setRating(trade.getFund().getRating());
            fundDTO.setCreateTime(trade.getFund().getCreateTime());
            fundDTO.setUpdateTime(trade.getFund().getUpdateTime());
            // 不设置 tags 字段，避免循环引用
            tradeDTO.setFund(fundDTO);
        }
        
        return tradeDTO;
    }

    private Trade convertToEntity(TradeDTO tradeDTO) {
        Trade trade = new Trade();
        BeanUtils.copyProperties(tradeDTO, trade, "id", "portfolio", "fund", "createTime", "updateTime");
        
        // 处理Portfolio
        if (tradeDTO.getPortfolio() != null) {
            Portfolio portfolio = null;
            
            // 尝试通过ID查找
            if (tradeDTO.getPortfolio().getId() != null) {
                Optional<Portfolio> portfolioOpt = portfolioRepository.findById(tradeDTO.getPortfolio().getId());
                if (portfolioOpt.isPresent()) {
                    portfolio = portfolioOpt.get();
                }
            }
            
            // 如果通过ID找不到，尝试通过名称查找
            if (portfolio == null && tradeDTO.getPortfolio().getName() != null) {
                portfolio = portfolioRepository.findByName(tradeDTO.getPortfolio().getName());
            }
            
            trade.setPortfolio(portfolio);
        }
        
        // 处理Fund
        if (tradeDTO.getFund() != null) {
            Fund fund = null;
            
            // 尝试通过ID查找
            if (tradeDTO.getFund().getId() != null) {
                Optional<Fund> fundOpt = fundRepository.findById(tradeDTO.getFund().getId());
                if (fundOpt.isPresent()) {
                    fund = fundOpt.get();
                }
            }
            
            // 如果通过ID找不到，尝试通过名称或代码查找
            if (fund == null) {
                if (tradeDTO.getFund().getName() != null) {
                    fund = fundRepository.findByName(tradeDTO.getFund().getName());
                } else if (tradeDTO.getFund().getCode() != null) {
                    Optional<Fund> fundOpt = fundRepository.findByCode(tradeDTO.getFund().getCode());
                    if (fundOpt.isPresent()) {
                        fund = fundOpt.get();
                    }
                }
            }
            
            trade.setFund(fund);
        }
        
        return trade;
    }
} 